package com.hexingmo.dawn.lang;

import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;

/**
 * @author He Xing Mo
 * @since 1.0
 */
public class ClassLoaders {

    private ClassLoaders() {
        throw new IllegalStateException("Static utility classes do not support instantiation");
    }

    /**
     * 检测传入的 Class 是否是由传入的 ClassLoader 所加载的。
     *
     * @param clazz 要检测的类
     * @param classLoader 要比较的类加载器
     * @return 如果 clazz 是由 classLoader 加载的则返回 true，否则返回 false
     */
    public static boolean isLoadedByClassLoader(Class<?> clazz, ClassLoader classLoader) {
        if (clazz == null || classLoader == null) {
            return false;
        }
        return clazz.getClassLoader() == classLoader;
    }

    public static ClassLoader getDefaultClassLoader() {
        ClassLoader cl = null;
        try {
            cl = getCurrentThreadClassLoader();
        }
        catch (Throwable ex) {
            // Cannot access thread context ClassLoader - falling back...
        }
        if (cl == null) {
            // No thread context class loader -> use current caller class loader of this class.
            cl = getCurrentCallerClassLoader();
            if (cl == null) {
                // getClassLoader() returning null indicates the application ClassLoader
                try {
                    cl = getApplicationClassLoader();
                }
                catch (Throwable ex) {
                    // Cannot access system ClassLoader - oh well, maybe the caller can live with null...
                }
            }
        }
        return cl;
    }

    @CallerSensitive
    public static ClassLoader getCurrentCallerClassLoader() {
        return Reflection.getCallerClass().getClassLoader();
    }

    /**
     * 获取当前线程的上下文类加载器。
     *
     * @return 当前线程的上下文类加载器
     */
    public static ClassLoader getCurrentThreadClassLoader() {
        return Thread.currentThread().getContextClassLoader();
    }

    /**
     * 获取启动类加载器（Bootstrap ClassLoader）。
     * 注意：启动类加载器无法直接获取，通过获取扩展类加载器的父类加载器来间接获取。
     *
     * @return 启动类加载器，返回 null
     */
    public static ClassLoader getBootstrapClassLoader() {
        return getExtensionClassLoader().getParent();
    }

    /**
     * 获取扩展类加载器（Extension ClassLoader）。
     *
     * @return 扩展类加载器
     */
    public static ClassLoader getExtensionClassLoader() {
        return sun.misc.Launcher.getLauncher().getClassLoader();
    }

    /**
     * 获取应用程序类加载器（Application ClassLoader）。
     *
     * @return 应用程序类加载器
     */
    public static ClassLoader getApplicationClassLoader() {
        return ClassLoader.getSystemClassLoader();
    }
}
